/*


    example-gpios {
        compatible = "osw,glink";
        gpios = <
				&gpio4 16 1  // a
				&gpio4 26 1  // b
				&gpio4 25 1  // c  
				&gpio4 27 1  // d
				&gpio4 28 1  // e
				&gpio4 14 1  // f
				&gpio1 27 1  // g
				
				&gpio1 26 1  // bit0
				&gpio3 25 1  // bit1
				&gpio3 26 1  // bit2
		>;
    };


    osw-glink {
        compatible = "osw,glink";
#if 1 // 1x32
		gpios = <
				&gpio1 1 1  // 0
				&gpio1 2 1  // 1
				&gpio1 3 1  // 2
				&gpio1 4 1  // 3 
				&gpio1 24 1  // 4
				&gpio1 25 1  // 5
				&gpio1 28 1  // 6 

				&gpio1 19 1  //  strobe 上升边沿有效
				&gpio1 29 1  // reset
		>;
#endif
    };

该驱动必须将ＬＩＮＵＸ的ｔｉｃｋ周期改成１ｍｓ否则数码管显示有残影

-> Kernel Features
- -> Timer frequency (<choice> [=y])  

CONFIG_HZ_1000=y
CONFIG_HZ=1000
*/
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/kthread.h>

#define NUM_GPIOS 9

#define I_SEG_A 0
#define I_SEG_B 1
#define I_SEG_C 2
#define I_SEG_D 3
#define I_SEG_E 4
#define I_SEG_F 5
#define I_SEG_G 6

#define BIT_0 7
#define BIT_1 8
#define BIT_2 9



#define I_BIT0 (0)
#define I_BIT1 (1)
#define I_BIT2 (2)
#define I_BIT3 (3)
#define I_BIT4 (4)
#define I_BIT5 (5)
// #define I_BIT6 (6)
#define I_STROBE (7)
#define I_RESET (8)

#define EN_BIT (0)

#define SEG_A  0b00000001
#define SEG_B  0b00000010
#define SEG_C  0b00000100
#define SEG_D  0b00001000
#define SEG_E  0b00010000
#define SEG_F  0b00100000
#define SEG_G  0b01000000

#define CNT_BATTERY (1)

static int gpios[NUM_GPIOS];
static struct timer_list example_timer_0;
static struct timer_list example_timer_1;
static struct timer_list example_timer_2;
static int current_gpio = 0;

const unsigned char segments[] = {
    SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,             // 0
    SEG_B | SEG_C,                                             // 1
    SEG_A | SEG_B | SEG_D | SEG_E | SEG_G,                     // 2
    SEG_A | SEG_B | SEG_C | SEG_D | SEG_G,                     // 3
    SEG_B | SEG_C | SEG_F | SEG_G,                             // 4
    SEG_A | SEG_C | SEG_D | SEG_F | SEG_G,                     // 5
    SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,             // 6
    SEG_A | SEG_B | SEG_C,                                     // 7
    SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,     // 8
    SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G              // 9
};






static struct miscdevice *pmisc;
struct product_data
{
	// char *board;
	struct miscdevice     *pmisc;
};

void fun_init(struct platform_device *pdev)
{
	int                    i;
	char                   name[16];
	struct device         *this_dev;
	struct miscdevice     *tpmisc;
	// struct misc_batt_data *pdata, *tpdata;
	struct product_data  *pdata;

	pdata = platform_get_drvdata(pdev);
	pdata->pmisc = devm_kzalloc(&pdev->dev, sizeof(struct miscdevice) * CNT_BATTERY, GFP_KERNEL);
	
	// pmisc = kzalloc(sizeof(struct miscdevice) * CNT_BATTERY, GFP_KERNEL);
	// pdata = kzalloc(sizeof(struct misc_batt_data) * CNT_BATTERY, GFP_KERNEL);

	tpmisc = pdata->pmisc;
	snprintf(name, sizeof(name), "led-dig");
	tpmisc->name  = name;
	tpmisc->minor = MISC_DYNAMIC_MINOR;
	tpmisc->fops  = NULL;
	misc_register(tpmisc);

	this_dev                = tpmisc->this_device;
	// this_dev = &pdev->dev;
	
	// this_dev->platform_data = tpdata;


	// strncpy(tpdata->name, name, sizeof(((struct misc_batt_data *)(0))->name));

	// device_create_file(this_dev, &dev_attr_config);
	// device_create_file(this_dev, &dev_attr_sn);
	// device_create_file(this_dev, &dev_attr_board);
	// device_create_file(this_dev, &dev_attr_boot_sha1);
	// device_create_file(this_dev, &dev_attr_boot_build);
}


void select_chn(int chx)
{
    // 0000 ch1
    // 0001 ch2
    // 0010 ch3
    // 0011 ch4
    int sn = (chx - 1) & 0x7f;  // 7个bit控制光开关
    // int sn = (chx ) & 0x7f;  // 7个bit控制光开关
    // printk("sn %x\r\n", sn);
    int i;
    for (i = 0;i < I_RESET; i++) {
        gpio_set_value(gpios[i], 0);
    }
    
    int bit;
    
    for (i = 0;i < I_RESET; i++) {
        bit = sn & 0x01;
        gpio_set_value(gpios[i], bit);
        sn = sn >> 1;
    }

    // dbg
    // for (i = 0;i < I_RESET; i++) {
    //     gpio_set_value(gpios[i], 1);
    // }
    // end dbg


    // gpio_set_value(gpios[chx], 0);
    // 上升沿数据有效
    gpio_set_value(gpios[I_STROBE], 0);
    msleep(10);
    gpio_set_value(gpios[I_STROBE], 1);
}
static char sn_value[20] = "1234567890";
static int sn_int = 0;
static ssize_t sn_show(struct device *dev, struct device_attribute *attr, char *buf)
{
    return sprintf(buf, "%s\n", sn_value);
}

static ssize_t sn_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
    // size_t len = min_t(size_t, count, sizeof(sn_value) - 1);
    // memcpy(sn_value, buf, len);
    // sn_value[len] = '\0';

    // return count;
    size_t len = min_t(size_t, count, sizeof(sn_value) - 1);
    int i;
    memcpy(sn_value, buf, len);
    sn_value[len] = '\0';


    sscanf(sn_value, "%d", &sn_int);
    select_chn(sn_int);
    return count;
}

static DEVICE_ATTR_RW(sn);

static struct attribute *example_attrs[] = {
    &dev_attr_sn.attr,
    NULL,
};

static const struct attribute_group example_attr_group = {
    .attrs = example_attrs,
};
void delay(int d)
{
    volatile int i;
    for (i = 0;i < 1000*d; i++) {

    }
}
static struct task_struct *my_thread;

int my_thread_func(void *data)
{
    int i, sn, j;

    // gpio_set_value(gpios[BIT_0], EN_BIT);
    // gpio_set_value(gpios[BIT_1], !EN_BIT);
    // gpio_set_value(gpios[BIT_2], !EN_BIT);
    int c = 4;
    while (!kthread_should_stop()) {
        // 在这里编写内核线程的逻辑
        // printk(KERN_INFO "Hello from kernel thread!\n");
        sn = sn_int;
        for (i = 0;i < NUM_GPIOS; i++) {
            gpio_set_value(gpios[i], EN_BIT);
        }
        msleep(10);
        for (i = 0;i < NUM_GPIOS; i++) {
            gpio_set_value(gpios[i], !EN_BIT);
        }
        msleep(10);
        // for (i = 0;i < NUM_GPIOS; i++) {
        //     gpio_set_value(gpios[i], 0);
        //     for (j = 0;j < 4; j++) {
        //         gpio_set_value(gpios[j], 1);
        //         msleep(1000);
        //     }
            
        // }
        // msleep(0);
    }

    return 0;
}

static int example_probe(struct platform_device *pdev)
{
    int i, ret;
    /* 从设备树加载GPIO引脚 */
    for (i = 0; i < NUM_GPIOS; i++) {
        // gpios[i] = of_get_gpio(pdev->dev.of_node, i);
        gpios[i]  = of_get_named_gpio(pdev->dev.of_node, "gpios", i);
        if (gpios[i] < 0) {
            dev_err(&pdev->dev, "Failed to get gpio %d\n", i);
            return gpios[i];
        }
        ret = devm_gpio_request(&pdev->dev, gpios[i], "led-digital");
        if (ret) {
            dev_err(&pdev->dev, "Failed to request gpio %d\n", i);
            return ret;
        }
        gpio_direction_output(gpios[i], 0);
        gpio_set_value(gpios[i], 0);
    }
    msleep(10);
    gpio_set_value(gpios[I_RESET], 1);
    // msleep(1000);
    // select_chn(2);
    /* 初始化定时器 */
    // timer_setup(&example_timer_0, example_timer_callback_0, 0);
    // mod_timer(&example_timer_0, jiffies + msecs_to_jiffies(1000));

    // timer_setup(&example_timer_2, example_timer_callback_2, 0);
    // mod_timer(&example_timer_2, jiffies + msecs_to_jiffies(1000));
    // fun_init(pdev);


    struct device *this_dev;
    // int ret;

    this_dev = &pdev->dev;

    ret = sysfs_create_group(&this_dev->kobj, &example_attr_group);
    if (ret) {
        dev_err(this_dev, "Failed to create sysfs attributes\n");
        return ret;
    }

    // my_thread = kthread_create(my_thread_func, NULL, "oswd");
    // if (IS_ERR(my_thread)) {
    //     printk(KERN_ERR "Failed to create kernel thread\n");
    //     return PTR_ERR(my_thread);
    // }

    // wake_up_process(my_thread); // 启动内核线程
    dev_info(this_dev, "Example driver probed\n");
    return 0;
}

void fun_exit(void )
{
		int i;
	struct miscdevice *tpmisc;

	if (pmisc) {
		tpmisc = pmisc;
		for (i = 0; i < CNT_BATTERY; i++) {
			misc_deregister(tpmisc);
			tpmisc++;
		}
		kfree(pmisc);
	}
}

static int example_remove(struct platform_device *pdev)
{
    struct device *this_dev = &pdev->dev;

    sysfs_remove_group(&this_dev->kobj, &example_attr_group);
    int i;

    /* 删除定时器 */
    del_timer_sync(&example_timer_0);
    del_timer_sync(&example_timer_2);

    for (i = 0; i < NUM_GPIOS; i++) {
        gpio_free(gpios[i]);
    }

        if (my_thread) {
        kthread_stop(my_thread); // 停止内核线程
    }

    return 0;
}

static const struct of_device_id example_of_match[] = {
    { .compatible = "osw,glink", },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, example_of_match);

static struct platform_driver example_driver = {
    .probe = example_probe,
    .remove = example_remove,
    .driver = {
        .name = "osw",
        .of_match_table = example_of_match,
    },
};
module_platform_driver(example_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Assistant");
MODULE_DESCRIPTION("Example device tree driven GPIO driver with timer");